From 0970077af90546a8d8198ceb64ad0572b9dd89f3 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 15 Jul 2020 20:28:45 +0200 Subject: [PATCH] stringsorter: Implement GtkSortKeys --- gtk/gtkstringsorter.c | 188 ++++++++++++++++++++++++++++++------------ 1 file changed, 137 insertions(+), 51 deletions(-) diff --git a/gtk/gtkstringsorter.c b/gtk/gtkstringsorter.c index 2879faf140..24244162a9 100644 --- a/gtk/gtkstringsorter.c +++ b/gtk/gtkstringsorter.c @@ -22,6 +22,7 @@ #include "gtkstringsorter.h" #include "gtkintl.h" +#include "gtksorterprivate.h" #include "gtktypebuiltins.h" /** @@ -58,70 +59,58 @@ G_DEFINE_TYPE (GtkStringSorter, gtk_string_sorter, GTK_TYPE_SORTER) static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; -static GtkOrdering -gtk_string_sorter_compare (GtkSorter *sorter, - gpointer item1, - gpointer item2) +static char * +gtk_string_sorter_get_key (GtkExpression *expression, + gboolean ignore_case, + gpointer item1) { - GtkStringSorter *self = GTK_STRING_SORTER (sorter); - GValue value1 = G_VALUE_INIT; - GValue value2 = G_VALUE_INIT; - const char *s1, *s2; - gboolean res1, res2; - GtkOrdering result; + GValue value = G_VALUE_INIT; + char *s; - if (self->expression == NULL) - return GTK_ORDERING_EQUAL; + if (expression == NULL) + return NULL; - res1 = gtk_expression_evaluate (self->expression, item1, &value1); - res2 = gtk_expression_evaluate (self->expression, item2, &value2); + if (!gtk_expression_evaluate (expression, item1, &value)) + return NULL; - /* If items don't evaluate, order them at the end, so they aren't - * in the way. */ - if (!res1) + /* If strings are NULL, order them before "". */ + if (ignore_case) { - result = res2 ? GTK_ORDERING_LARGER : GTK_ORDERING_EQUAL; - goto out; + char *t; + + t = g_utf8_casefold (g_value_get_string (&value), -1); + s = g_utf8_collate_key (t, -1); + g_free (t); } - else if (!res2) + else { - result = GTK_ORDERING_SMALLER; - goto out; + s = g_utf8_collate_key (g_value_get_string (&value), -1); } - s1 = g_value_get_string (&value1); - s2 = g_value_get_string (&value2); + g_value_unset (&value); - /* If strings are NULL, order them before "". */ - if (s1 == NULL) - { - result = s2 == NULL ? GTK_ORDERING_EQUAL : GTK_ORDERING_SMALLER; - goto out; - } - else if (s2 == NULL) - { - result = GTK_ORDERING_LARGER; - goto out; - } + return s; +} - if (self->ignore_case) - { - char *t1, *t2; +static GtkOrdering +gtk_string_sorter_compare (GtkSorter *sorter, + gpointer item1, + gpointer item2) +{ + GtkStringSorter *self = GTK_STRING_SORTER (sorter); + char *s1, *s2; + GtkOrdering result; - t1 = g_utf8_casefold (s1, -1); - t2 = g_utf8_casefold (s2, -1); + if (self->expression == NULL) + return GTK_ORDERING_EQUAL; - result = gtk_ordering_from_cmpfunc (g_utf8_collate (t1, t2)); + s1 = gtk_string_sorter_get_key (self->expression, self->ignore_case, item1); + s2 = gtk_string_sorter_get_key (self->expression, self->ignore_case, item2); - g_free (t1); - g_free (t2); - } - else - result = gtk_ordering_from_cmpfunc (g_utf8_collate (s1, s2)); + result = gtk_ordering_from_cmpfunc (g_strcmp0 (s1, s2)); -out: - g_value_unset (&value1); - g_value_unset (&value2); + g_free (s1); + g_free (s2); return result; } @@ -137,6 +126,95 @@ gtk_string_sorter_get_order (GtkSorter *sorter) return GTK_SORTER_ORDER_PARTIAL; } +typedef struct _GtkStringSortKeys GtkStringSortKeys; +struct _GtkStringSortKeys +{ + GtkSortKeys keys; + + GtkExpression *expression; + gboolean ignore_case; +}; + +static void +gtk_string_sort_keys_free (GtkSortKeys *keys) +{ + GtkStringSortKeys *self = (GtkStringSortKeys *) keys; + + gtk_expression_unref (self->expression); + g_slice_free (GtkStringSortKeys, self); +} + +static int +gtk_string_sort_keys_compare (gconstpointer a, + gconstpointer b, + gpointer unused) +{ + const char *sa = *(const char **) a; + const char *sb = *(const char **) b; + + if (sa == NULL) + return sb == NULL ? GTK_ORDERING_EQUAL : GTK_ORDERING_LARGER; + else if (sb == NULL) + return GTK_ORDERING_SMALLER; + + return gtk_ordering_from_cmpfunc (strcmp (sa, sb)); +} + +static gboolean +gtk_string_sort_keys_is_compatible (GtkSortKeys *keys, + GtkSortKeys *other) +{ + return FALSE; +} + +static void +gtk_string_sort_keys_init_key (GtkSortKeys *keys, + gpointer item, + gpointer key_memory) +{ + GtkStringSortKeys *self = (GtkStringSortKeys *) keys; + char **key = (char **) key_memory; + + *key = gtk_string_sorter_get_key (self->expression, self->ignore_case, item); +} + +static void +gtk_string_sort_keys_clear_key (GtkSortKeys *keys, + gpointer key_memory) +{ + char **key = (char **) key_memory; + + g_free (*key); +} + +static const GtkSortKeysClass GTK_STRING_SORT_KEYS_CLASS = +{ + gtk_string_sort_keys_free, + gtk_string_sort_keys_compare, + gtk_string_sort_keys_is_compatible, + gtk_string_sort_keys_init_key, + gtk_string_sort_keys_clear_key, +}; + +static GtkSortKeys * +gtk_string_sort_keys_new (GtkStringSorter *self) +{ + GtkStringSortKeys *result; + + if (self->expression == NULL) + return gtk_sort_keys_new_equal (); + + result = gtk_sort_keys_new (GtkStringSortKeys, + >K_STRING_SORT_KEYS_CLASS, + sizeof (char *), + sizeof (char *)); + + result->expression = gtk_expression_ref (self->expression); + result->ignore_case = self->ignore_case; + + return (GtkSortKeys *) result; +} + static void gtk_string_sorter_set_property (GObject *object, guint prop_id, @@ -239,6 +317,10 @@ static void gtk_string_sorter_init (GtkStringSorter *self) { self->ignore_case = TRUE; + + gtk_sorter_changed_with_keys (GTK_SORTER (self), + GTK_SORTER_CHANGE_DIFFERENT, + gtk_string_sort_keys_new (self)); } /** @@ -306,7 +388,9 @@ gtk_string_sorter_set_expression (GtkStringSorter *self, if (expression) self->expression = gtk_expression_ref (expression); - gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT); + gtk_sorter_changed_with_keys (GTK_SORTER (self), + GTK_SORTER_CHANGE_DIFFERENT, + gtk_string_sort_keys_new (self)); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXPRESSION]); } @@ -345,7 +429,9 @@ gtk_string_sorter_set_ignore_case (GtkStringSorter *self, self->ignore_case = ignore_case; - gtk_sorter_changed (GTK_SORTER (self), ignore_case ? GTK_SORTER_CHANGE_LESS_STRICT : GTK_SORTER_CHANGE_MORE_STRICT); + gtk_sorter_changed_with_keys (GTK_SORTER (self), + ignore_case ? GTK_SORTER_CHANGE_LESS_STRICT : GTK_SORTER_CHANGE_MORE_STRICT, + gtk_string_sort_keys_new (self)); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_IGNORE_CASE]); } -- 2.30.2